#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<signal.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <memory.h>

#define BUFSIZE 512*1024

// g1.全局的互斥量
pthread_mutex_t g_mutex;
pthread_cond_t  g_cond;   // 控制线程
pthread_cond_t  g_cond_226; bool g_flag_226 = false; pthread_mutex_t g_mutex_226;
// g2.使用Proxy进行中转传输的俩socket
typedef struct {
   int m_SocketSrc;
   int m_SocketDest;
}Two_Sockets;

typedef struct{
   int m_ClientCtrlSocket;
   char m_ProxyCtrlBuf[BUFSIZE];
}DataThreadUse;
// g3.数据暂存区 m_Buf[][0] -- 控制 m_Buf[][1] -- 数据
char m_ProxyBuf[2][BUFSIZE] = {0};
// g4.全局Socket
int g_ListenCtrlSocket = 0; // Proxy - wait accept
int g_ListenDataSocket = 0; // Proxy - wait accept
int g_ConSerCtrlSocket = 0; // Server - connect FtpServer
int g_ConSerDataSocket = 0; // Server - connect FtpServer
// g5.全局IP+Port
char g_ConSerIP[32];
int  g_ConSerPort[2];     // 传输数据的时候用
char g_LocalIP[32];    // 本机地址
int  g_LocalPort[2];   // Proxy提供俩端口
// g6.

// 函数声明
int GetLocalListenSocket(int nLocalPort);
int GetConnectSerSocket(char* pSerIP, int pSerPort);
void ClientProxyFtpServer(); // -- 这里开始创建控制线程
void AnalysisFtpServerBuf(char* pStr,int length);
void ModifyFtpServerADDRBuf(char* pStr, int length);
// 线程函数声明
void *TranCtrlSocketThread(void* pParams);
// 测试函数
void *testClientConnectProxy_1(void* pArgv);


int main(int argc, char** argv)
{
        // Initial
        const char *pArgv[] = {
           " ",
           "4000",
           "4007",
           "192.168.56.1",
           "21",
           "10,0,2,15"
        };
        strcpy(g_LocalIP, pArgv[5]);
        g_LocalPort[0] = atoi(pArgv[1]); // Proxy Control Listen Port
        g_LocalPort[1] = atoi(pArgv[2]); // Proxy Data    Listen Port
        strcpy(g_ConSerIP, pArgv[3]); // FtpServer IP
        g_ConSerPort[0] = atoi(pArgv[4]);
        // ListenSocket -- one for Control, the other for Data
        if((g_ListenCtrlSocket=GetLocalListenSocket(g_LocalPort[0]))==0){
               printf("Sorry! Listen [%d] error!\n",g_LocalPort[0]);
               exit(1); // 不用关闭--因为函数处理了
        }
        if((g_ListenDataSocket=GetLocalListenSocket(g_LocalPort[1]))==0){
               printf("Sorry! Listen [%d] error!\n",g_LocalPort[1]);
               exit(1);
        }
        // 监听之后，接下来，就是处理接受客户端的连接和连接服务器端
        ClientProxyFtpServer();
        return 0;
}


/**
 *   1. 获取本机的监听Socket   -------  监听（1）
 *      params: nLocalPort -- 本机端口
 */
int GetLocalListenSocket(int nLocalPort)
{
        // 1. 用本机地址和相应的端口建立监听的socket
        struct sockaddr_in tempAddr = {0};
        int    tempAddrLen = sizeof(struct sockaddr_in);
        int    tempBackSocket = 0;

        tempAddr.sin_family = AF_INET;
        tempAddr.sin_addr.s_addr = INADDR_ANY;
        tempAddr.sin_port = htons(nLocalPort);

        // socket
        if((tempBackSocket=socket(AF_INET,SOCK_STREAM,0))<0){
              return 0;
        }
        // bind
        if(bind(tempBackSocket,(struct sockaddr*)&tempAddr,tempAddrLen)<0){
              return 0;
        }
        // listen
        if(listen(tempBackSocket,5)){
              close(tempBackSocket);
              return 0;
        }
        return tempBackSocket;
}

/**
 *   1.1 . 等待连接  -----------------  接受连接（2）
 *         pSerIP   -- FtpServerIP
 *         pSerPort -- FtpServerPort
 */
int AcceptWaitConnect(int ListenSocket)
{
        struct sockaddr_in tempClientAddr = {0};
        int    tempClientAddrLen = sizeof(struct sockaddr_in);
        int    tempAcceptSocket = 0;
        tempAcceptSocket = accept(ListenSocket,(struct sockaddr*)&tempClientAddr,(socklen_t*)&tempClientAddrLen);
        return tempAcceptSocket;
}

/**
 *   2. 获取FtpServer的Socket  -------- 连接（2）
 *      pSerIP   -- FtpServerIP
 *      pSerPort -- FtpServerPort
 */
 int GetConnectSerSocket(char* pSerIP, int pSerPort)
 {
        struct sockaddr_in tempAddr = {0};
        int    tempAddrLen = sizeof(sockaddr_in);
        int    tempBackSocket = 0;

        tempAddr.sin_family = AF_INET;
        tempAddr.sin_addr.s_addr = inet_addr(pSerIP);
        tempAddr.sin_port = htons(pSerPort);

        // socket
        if((tempBackSocket=socket(AF_INET,SOCK_STREAM,0))<0){
              return 0;
        }
        // connect
        if(connect(tempBackSocket,(struct sockaddr*)&tempAddr, tempAddrLen)<0){
              close(tempBackSocket);
              return 0;
        }
        return tempBackSocket;
 }

/**
 *   3. 客户端连接Fpt服务器--控制
 *      Proxy接受(accept)客户端的连接，并且主动连接（connect)FtpServer
 *      然后创建俩线程去完成1.服务器到代理到客户端 2.客户端到代理到服务器
 */
 void ClientProxyFtpServer()
 {
        // 3.1. 接受客户端的连接请求
        int tempClientSocket = 0;
        // 3.2 阻塞，等待连接
        #ifndef __DEBUG__
        printf("等待客户端连接........\n");
        #endif
        tempClientSocket = AcceptWaitConnect(g_ListenCtrlSocket);
        // 3.3 连接Ftp服务器
        int tempFtpServerSocket = 0;
        tempFtpServerSocket = GetConnectSerSocket(g_ConSerIP, g_ConSerPort[0]);
        if(tempFtpServerSocket==0){
              close(g_ListenCtrlSocket);
              close(g_ListenDataSocket);
              printf("连接Ftp服务器失败.......\n");
              exit(1);
        }
        // 3.4 新建俩线程-1，用来监听服务器代理客户端的数据； 2.用来监听客户端代理服务器的数据
        //     tempClientSocket, tempFtpServerSocket
        Two_Sockets tempTwoSockets[2];
        //     tempTwoSockets[0] - 服务器代理客户端
        tempTwoSockets[0].m_SocketSrc  = tempClientSocket;
        tempTwoSockets[0].m_SocketDest = tempFtpServerSocket;
        //     tempTwoSockets[1] - 客户端代理服务器
        tempTwoSockets[1].m_SocketSrc  = tempFtpServerSocket;
        tempTwoSockets[1].m_SocketDest = tempClientSocket;
        //     条件变量
        pthread_cond_init(&g_cond,NULL);
        pthread_mutex_init(&g_mutex, NULL);
        //g_cond = PTHREAD_COND_INITIALIZER;
        //g_mutex = PTHREAD_MUTEX_INITIALIZER;
        //     俩线程
        pthread_t pClient, pFtpServer;
        pthread_create(&pFtpServer, NULL, TranCtrlSocketThread, (void*)&tempTwoSockets[0]);
        pthread_create(&pClient, NULL, TranCtrlSocketThread, (void*)&tempTwoSockets[1]);
        #ifndef __DEBUG__
        printf("Create Thread [%x]-----Mian1---------\n", (unsigned)pFtpServer);
        printf("Create Thread [%x]-----Mian2---------\n", (unsigned)pClient);
        #endif
        // 3.5 善后
        //pthread_mutex_lock(&g_mutex);
        pthread_cond_wait(&g_cond,&g_mutex);
        //pthread_mutex_unlock(&g_mutex);

        close(g_ListenCtrlSocket);
        close(g_ListenDataSocket);
        close(tempClientSocket);
        close(tempFtpServerSocket);
}

/**
 *   4. 线程函数
 *      端 -- 代理 -- 端
 */
void *TranCtrlSocketThread(void* pParams)
{
        Two_Sockets *pSendRecvSockets = (Two_Sockets*)pParams;
        int m_SendSocket = pSendRecvSockets->m_SocketSrc;
        int m_RecvSocket = pSendRecvSockets->m_SocketDest;
        int nRecvDataLen = 0;
        pthread_t pDataID;
        while(1){
              // 4.1 服务器返回数据到代理
              //     当接收的数据长度<=0时退出
              nRecvDataLen = recv(m_RecvSocket, m_ProxyBuf[0], BUFSIZE-1, 0);
              if(nRecvDataLen<=0){
                  // 说明断开了 -- 结束线程
                  // 发个信号，告诉其已结束
                  pthread_cond_signal(&g_cond);
                  //pthread_join(pDataID,NULL);
                  pthread_exit(0);
              }
              m_ProxyBuf[0][nRecvDataLen] = '\0';

              if(m_ProxyBuf[0][0]>='0'&&m_ProxyBuf[0][0]<='9'){
                  #ifndef __DEBUG__
                  printf("服务器发给客户端的数据---------\n");
                  printf("%s\n",m_ProxyBuf[0]);
                  printf("---------------------------\n");
                  #endif
                  // 解析服务器的响应的数据
                  AnalysisFtpServerBuf(m_ProxyBuf[0], nRecvDataLen);
                  // test_1 -- 只是为了测试是否有连接
                  if(strncmp(m_ProxyBuf[0],"227",3)==0){
                         pthread_cond_init(&g_cond_226,NULL);
                         pthread_mutex_init(&g_mutex_226,NULL);
                         pthread_create(&pDataID,NULL,testClientConnectProxy_1,(void *)&m_SendSocket);
                         #ifndef __DEBUG__
                         printf("Create Thread [%x]-----Data---------\n", (unsigned)pDataID);
                         #endif
                  }

                  if(strncmp(m_ProxyBuf[0],"226",3)==0){
                         // 等待Proxy把数据发送完
                         continue;
                  }
              }else{
                        #ifndef __DEBUG__
                        printf("客户端发送给服务器的数据---------\n");
                        printf("%s\n",m_ProxyBuf[0]);
                        printf("---------------------------\n");
                        #endif
              }
              // 4.3 代理向客户端发送数据
              send(m_SendSocket, m_ProxyBuf[0], nRecvDataLen, 0);
        }

}

/**
 *   5.分析FtpServer返回的数据-
 *     如：227--修改(192,168,56,1,24,12) -> (10,0,2,15,21,21);
 */
void AnalysisFtpServerBuf(char* pStr, int length)
{
        if(strncmp(pStr,"227",3)==0){
              // 1.得到FtpServer的端口并修改
              char *pEnd   = pStr + length;
              while(*pEnd != ')')
                 pEnd--;
              char *pBegin = pEnd;
              while(*pBegin != ',')
                 pBegin--;
              char  numBuf[7];
              memset(numBuf,'\0',7);
              strncpy(numBuf,pBegin+1, pEnd-pBegin+1);
              int numSecond = atoi(numBuf);
              pEnd = pBegin - 1;
              while(*pEnd != ',')
                 pEnd--;
              memset(numBuf,'\0',7);
              strncpy(numBuf,pEnd+1, pBegin-pEnd-1);
              int numFirst = atoi(numBuf);
              g_ConSerPort[1] = numFirst*256 + numSecond;
              #ifndef __DEBUG__
              printf("DataPort::%d---------------------\n", g_ConSerPort[1]);
              #endif
              // 2. 修改数据
              ModifyFtpServerADDRBuf(pStr, length);
        }// end if
}

/**
 *    6. 修改FtpServer返回的227中的ip和port
 *
 */
void ModifyFtpServerADDRBuf(char* pStr, int length)
{
        char *pBegin = pStr;
        int   nCount1 = 0, nCount2 = 0;
        while(*pBegin!='('){
              pBegin++;
              nCount1++;
        }
        char *pEnd   = pBegin;
        while(*pEnd!=')'){
              pEnd++;
              nCount2++;
        }
        // 端口
        char proxyPortFirst[7];
        char proxyPortSecond[7];
        sprintf(proxyPortFirst, "%d", g_LocalPort[1]/256);
        sprintf(proxyPortSecond,"%d", g_LocalPort[1]%256);
        char tempModifyBuf[BUFSIZE];
        strncpy(tempModifyBuf, pStr, nCount1+1);
        strcat(tempModifyBuf, g_LocalIP);
        strcat(tempModifyBuf, ",");
        strcat(tempModifyBuf, proxyPortFirst);
        strcat(tempModifyBuf, ",");
        strcat(tempModifyBuf, proxyPortSecond);
        strcat(tempModifyBuf, pEnd);
        strcpy(pStr, tempModifyBuf);
        #ifndef __DEBUG__
        printf("修改的227内容--------------\n");
        printf("%s\n",pStr);
        printf("----------------------\n");
        #endif
}
/**
 *    T1. 测试客户端是否连接了Proxy的4007端口
 */
void *testClientConnectProxy_1(void* pArgv)
{
        int m_ClientCtrlSocket = *((int*)pArgv);
        //pthread_mutex_lock(&g_mutex);
        // 1.接受客户端的数据连接
        int tempDataClientSocket = 0;
        #ifndef __DEBUG__
        printf("Proxy打开的数据端口等待客户端连接....\n");
        #endif
        tempDataClientSocket = AcceptWaitConnect(g_ListenDataSocket);
        #ifndef __DEBUG__
        printf("Proxy打开的数据端口被客户端连接了......\n");
        #endif
        //pthread_exit(0);
        // 2.这时，Proxy要主动去连接Ftp服务器的数据端口

        int tempDataServerSocket = 0;
        tempDataServerSocket = GetConnectSerSocket(g_ConSerIP, g_ConSerPort[1]);
        #ifndef __DEBUG__
        printf("服务器打开的数据端口被Proxy连接....\n");
        #endif
        // 3. 这时就可以进行你数据传输了
        int nRecvDataLen = 0;
        #ifndef __DEBUG__
        printf("---------------DataExanchange Begin!-------------------\n");
        #endif

        nRecvDataLen = recv(tempDataServerSocket, m_ProxyBuf[1], BUFSIZE-1, 0);
        if(nRecvDataLen<=0){
                pthread_exit(0);
        }
        m_ProxyBuf[1][nRecvDataLen] = '\0';
        #ifndef __DEBUG__
        printf("从服务器获取的数据------------------------------------\n");
        printf("%s", m_ProxyBuf[1]);
        printf("----------------------------------------\n");
        #endif
        send(tempDataClientSocket, m_ProxyBuf[1], nRecvDataLen, 0);
        #ifndef __DEBUG__
        printf("发给客户端数据成功------------------------------------\n");
        printf("%s", m_ProxyBuf[1]);
        printf("----------------------------------------\n");
        #endif
        close(tempDataServerSocket);
        close(tempDataClientSocket);
        send(m_ClientCtrlSocket, m_ProxyBuf[0], strlen(m_ProxyBuf[0]),0);
        //close(m_ClientCtrlSocket); -- I'm stupid!
        pthread_exit(0);
}


/**
 *
 */






















